﻿/**
 * @file XPDF_wrapper.h
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-12-16
 * @version : 1.0.0.0
 * @brief   : 使用 PDFium 库，实现 PDF 简单操作的几个工具类。
 */

#ifndef __PDF_WRAPPER_H__
#define __PDF_WRAPPER_H__

#ifndef __XTYPES_H__
#error "Please include xtypes.h before including this file."
#endif // __XTYPES_H__

#include <string>

////////////////////////////////////////////////////////////////////////////////

/**********************************************************/
/**
 * @brief 加载 PDFium 库的操作接口。
 * 
 * @param [in ] xszt_lib_path : PDFium 动态库的文件路径名。
 * @param [in ] xpvt_reserved : 保留参数（设置为 X_NULL）。
 * 
 * @return x_int32_t 
*         - 成功，返回 0；
*         - 失败，返回 错误码。
 */
x_int32_t XPDF_load(x_cstring_t xszt_lib_path, x_pvoid_t xpvt_reserved);

/**********************************************************/
/**
 * @brief 反初始化（卸载） PDFium 库的操作接口。
 */
x_void_t XPDF_unload(void);

////////////////////////////////////////////////////////////////////////////////
// XPDF_reader_t

/**
 * @class XPDF_reader_t
 * @brief 实现简单的 PDF 文件读操作类，用于 PDF 页面渲染操作。
 */
class XPDF_reader_t
{
    // common data types
public:
    /**
     * @enum  xerrno_table_t
     * @brief 错误码表。
     */
    typedef enum __errno_table__
    {
        //======================================
        // open() 接口产生的错误码

        X_ERR_OPEN_PDFLIB_NOT_LOADED   = 0x00000001,  ///< 尚未加载 PDF 库
        X_ERR_OPEN_ALREADY_OPENED      = 0x00000002,  ///< 对象已经打开
        X_ERR_OPEN_PARAM_INVALID       = 0x00000003,  ///< 输入参数无效
        X_ERR_OPEN_FILE_OPEN_ACCESSOR  = 0x00000004,  ///< 创建文件访问器对象失败

        //======================================
        // get_page_size() 接口产生的错误码

        X_ERR_GPZ_PDFLIB_NOT_LOADED    = 0x00000101,  ///< 尚未加载 PDF 库
        X_ERR_GPZ_UNOPENED             = 0x00000102,  ///< 对象尚未打开
        X_ERR_GPZ_PARAM_INVALID        = 0x00000103,  ///< 输入参数无效
        X_ERR_GPZ_DOC_ISNULL           = 0x00000104,  ///< 文档操作句柄为 X_NULL
        X_ERR_GPZ_XFUNC_PAGESIZE       = 0x00000105,  ///< 调用库函数 GetPageSizeByIndex() 时失败

        //======================================
        // get_page_size_ex() 接口产生的错误码

        X_ERR_GPZEX_PDFLIB_NOT_LOADED  = 0x00000201,  ///< 尚未加载 PDF 库
        X_ERR_GPZEX_UNOPENED           = 0x00000202,  ///< 对象尚未打开
        X_ERR_GPZEX_PARAM_INVALID      = 0x00000203,  ///< 输入参数无效

        //======================================
        // render_page() 接口产生的错误码

        X_ERR_RENDER_PDFLIB_NOT_LOADED = 0x00000301,  ///< 尚未加载 PDF 库
        X_ERR_RENDER_UNOPENED          = 0x00000302,  ///< 对象尚未打开
        X_ERR_RENDER_PARAM_INVALID     = 0x00000303,  ///< 输入参数无效
        X_ERR_RENDER_CALC_PAGESIZE     = 0x00000304,  ///< 计算页面合适尺寸时失败

        //======================================
        // doc_load() 接口产生的错误码

        X_ERR_FLOAD_XFUNC_AVAIL_CREATE     = 0x00001101,  ///< Avail_Create() 接口操作失败
        X_ERR_FLOAD_XFUNC_AVAIL_ISDOCAVAIL = 0x00001102,  ///< Avail_IsDocAvail() 接口操作失败
        X_ERR_FLOAD_PDFLOAD_DOCUMENT       = 0x00001103,  ///< 加载文档对象时操作失败

        //======================================
        // page_load() 接口产生的错误码

        X_ERR_PLOAD_PAGE_INAVAIL           = 0x00001201,  ///< 请求的页面无效
        X_ERR_PLOAD_PAGE_LDFAILED          = 0x00001202,  ///< 请求的页面加载失败

        //======================================
        // auto_resize_bitmap() 接口产生的错误码

        X_ERR_ARBMP_XFUNC_BITMAP_CREATE    = 0x00001301,  ///< Bitmap_Create() 接口操作失败

        //======================================

    } xerrno_table_t;

    // common invoking
public:
    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_int32_t xit_errno)
    {
        x_cstring_t xszt_name = "UNDEFIND NAME";

        switch (xit_errno)
        {
        //======================================
        // open() 接口产生的错误码

        case X_ERR_OPEN_PDFLIB_NOT_LOADED  : xszt_name = "X_ERR_OPEN_PDFLIB_NOT_LOADED" ; break;
        case X_ERR_OPEN_ALREADY_OPENED     : xszt_name = "X_ERR_OPEN_ALREADY_OPENED"    ; break;
        case X_ERR_OPEN_PARAM_INVALID      : xszt_name = "X_ERR_OPEN_PARAM_INVALID"     ; break;
        case X_ERR_OPEN_FILE_OPEN_ACCESSOR : xszt_name = "X_ERR_OPEN_FILE_OPEN_ACCESSOR"; break;

        //======================================
        // get_page_size() 接口产生的错误码

        case X_ERR_GPZ_PDFLIB_NOT_LOADED : xszt_name = "X_ERR_GPZ_PDFLIB_NOT_LOADED"; break;
        case X_ERR_GPZ_UNOPENED          : xszt_name = "X_ERR_GPZ_UNOPENED"         ; break;
        case X_ERR_GPZ_PARAM_INVALID     : xszt_name = "X_ERR_GPZ_PARAM_INVALID"    ; break;
        case X_ERR_GPZ_DOC_ISNULL        : xszt_name = "X_ERR_GPZ_DOC_ISNULL"       ; break;
        case X_ERR_GPZ_XFUNC_PAGESIZE    : xszt_name = "X_ERR_GPZ_XFUNC_PAGESIZE"   ; break;

        //======================================
        // get_page_size_ex() 接口产生的错误码

        case X_ERR_GPZEX_PDFLIB_NOT_LOADED  : xszt_name = "X_ERR_GPZEX_PDFLIB_NOT_LOADED"; break;
        case X_ERR_GPZEX_UNOPENED           : xszt_name = "X_ERR_GPZEX_UNOPENED"         ; break;
        case X_ERR_GPZEX_PARAM_INVALID      : xszt_name = "X_ERR_GPZEX_PARAM_INVALID"    ; break;

        //======================================
        // render_page() 接口产生的错误码

        case X_ERR_RENDER_PDFLIB_NOT_LOADED : xszt_name = "X_ERR_RENDER_PDFLIB_NOT_LOADED"; break;
        case X_ERR_RENDER_UNOPENED          : xszt_name = "X_ERR_RENDER_UNOPENED"         ; break;
        case X_ERR_RENDER_PARAM_INVALID     : xszt_name = "X_ERR_RENDER_PARAM_INVALID"    ; break;
        case X_ERR_RENDER_CALC_PAGESIZE     : xszt_name = "X_ERR_RENDER_CALC_PAGESIZE"    ; break;

        //======================================
        // doc_load() 接口产生的错误码

        case X_ERR_FLOAD_XFUNC_AVAIL_CREATE     : xszt_name = "X_ERR_FLOAD_XFUNC_AVAIL_CREATE"    ; break;
        case X_ERR_FLOAD_XFUNC_AVAIL_ISDOCAVAIL : xszt_name = "X_ERR_FLOAD_XFUNC_AVAIL_ISDOCAVAIL"; break;
        case X_ERR_FLOAD_PDFLOAD_DOCUMENT       : xszt_name = "X_ERR_FLOAD_PDFLOAD_DOCUMENT"      ; break;

        //======================================
        // page_load() 接口产生的错误码

        case X_ERR_PLOAD_PAGE_INAVAIL  : xszt_name = "X_ERR_PLOAD_PAGE_INAVAIL" ; break;
        case X_ERR_PLOAD_PAGE_LDFAILED : xszt_name = "X_ERR_PLOAD_PAGE_LDFAILED"; break;

        //======================================
        // auto_resize_bitmap() 接口产生的错误码

        case X_ERR_ARBMP_XFUNC_BITMAP_CREATE    : xszt_name = "X_ERR_ARBMP_XFUNC_BITMAP_CREATE"; break;

        //======================================

        default: break;
        }

        return xszt_name;
    }

    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_errno_t xerr_no)
    {
        return xerrno_name(XERR_HINO(xerr_no));
    }

    // constructor/destuctor
public:
    XPDF_reader_t(void);
    ~XPDF_reader_t(void);

    // public interfaces
public:
    /**********************************************************/
    /**
     * @brief 打开操作。
     * 
     * @param [in ] xszt_path   : PDF 文件路径。
     * @param [in ] xszt_passwd : 文件密码（仅对加密的 PDF 文件设置）。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t open(
                x_cstring_t xszt_path,
                x_cstring_t xszt_passwd);

    /**********************************************************/
    /**
     * @brief 关闭操作。
     */
    x_void_t close(void);

    /**********************************************************/
    /**
     * @brief 对象是否处于打开状态。
     */
    inline x_bool_t is_open(void) const
    {
        return (X_NULL != m_xht_faccess);
    }

    /**********************************************************/
    /**
     * @brief 获取页面数量。
     */
    inline x_int32_t get_page_count(void) const
    {
        return m_xit_page_count;
    }

    /**********************************************************/
    /**
     * @brief 获取页面尺寸。
     * 
     * @param [in ] xit_page_no : 页面序号（起始序号为 0）。
     * @param [out] xlft_cx     : 操作成功返回的页面宽度。
     * @param [out] xlft_cy     : 操作成功返回的页面高度。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t get_page_size(
                x_int32_t xit_page_no,
                x_lfloat_t & xlft_cx,
                x_lfloat_t & xlft_cy) const;

    /**********************************************************/
    /**
     * @brief 获取页面尺寸。
     * 
     * @param [in ] xit_page_no : 页面序号（起始序号为 0）。
     * @param [out] xlft_cx     : 操作成功返回的页面宽度。
     * @param [out] xlft_cy     : 操作成功返回的页面高度。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t get_page_size_ex(
                x_int32_t xit_page_no,
                x_lfloat_t & xlft_cx,
                x_lfloat_t & xlft_cy);

    /**********************************************************/
    /**
     * @brief 渲染指定的页面。
     * 
     * @param [in    ] xit_page_no : 页面序号（起始序号为 0）。
     * @param [in    ] xft_pgzoom  : 页面宽高的缩放倍数（如可取 1.0F，2.0F 等值）。
     * @param [in,out] xut_cx      : 页面宽度（入参，表示页面渲染操作的最大宽度，
     *                               为 0 时，取实际缩放后宽度；
     *                               回参，渲染操作返回的实际图像宽度）。
     * @param [in,out] xut_cy      : 页面高度（入参，表示页面渲染操作的最大高度，
     *                               为 0 时，取实际缩放后高度；
     *                               回参，渲染操作返回的实际图像高度）。
     * @param [out   ] xbits_ptr   : 操作成功返回的图像像素数据缓存地址。
     * @param [out   ] xit_pitch   : 操作成功返回的图像行扫描（字节）步进长度。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t render_page(
                x_int32_t xit_page_no,
                x_float_t xft_pgzoom,
                x_uint32_t & xut_cx,
                x_uint32_t & xut_cy,
                x_pvoid_t & xbits_ptr,
                x_int32_t & xit_pitch);

    // inner invoking
protected:
    /**********************************************************/
    /**
     * @brief 加载文件其他相关的操作句柄。
     */
    x_errno_t doc_load(x_cstring_t xszt_passwd);

    /**********************************************************/
    /**
     * @brief 释放文件其他相关的操作句柄。
     */
    x_void_t doc_free(void);

    /**********************************************************/
    /**
     * @brief 加载页面。
     */
    x_errno_t page_load(x_handle_t & xht_page, x_int32_t xit_page_no);

    /**********************************************************/
    /**
     * @brief 释放页面。
     */
    x_void_t page_free(x_handle_t xht_page);

    /**********************************************************/
    /**
     * @brief 自动调整 渲染操作使用的缓存位图对象 的宽高。
     */
    x_errno_t auto_resize_bitmap(x_uint32_t xut_cx, x_uint32_t xut_cy);

    // data members
private:
    std::string     m_sz_filename;       ///< 当前操作的文件名

    x_handle_t      m_xht_faccess;       ///< 文件访问器句柄
    x_handle_t      m_xht_favalid;       ///< 文件有效检测句柄
    x_handle_t      m_xht_fdhinst;       ///< 文件加载句柄
    x_handle_t      m_xht_fdocument;     ///< 文件构建的文档描述句柄
    x_handle_t      m_xht_xavalid;       ///< 有效操作的检测句柄
    x_int32_t       m_xit_page_count;    ///< 文件页面数量

    x_handle_t      m_xht_bitmap;        ///< 渲染操作使用的缓存位图对象
    x_uint32_t      m_xut_bmpcx;         ///< 当前缓存位图对象渲染使用到的宽度
    x_uint32_t      m_xut_bmpcy;         ///< 当前缓存位图对象渲染使用到的高度
};

////////////////////////////////////////////////////////////////////////////////
// XPDF_writer_t

/**
 * @class XPDF_writer_t
 * @brief 实现简单的 PDF 文件写操作类，主要使用 图片 作为 页面填充内容。
 */
class XPDF_writer_t
{
    // common data types
public:
    /**
     * @enum  xerrno_table_t
     * @brief 错误码表。
     */
    typedef enum __errno_table__
    {
        //======================================
        // create() 接口产生的错误码

        X_ERR_CREATE_PDFLIB_NOT_LOADED   = 0x00000001,  ///< 尚未加载 PDF 库
        X_ERR_CREATE_XFUNC_CREATENEWDOC  = 0x00000002,  ///< CreateNewDocument() 返回 X_NULL

        //======================================
        // insert_page_by_rgb32() 接口产生的错误码

        X_ERR_IPRGB_PDFLIB_NOT_LOADED    = 0x00000101,  ///< 尚未加载 PDF 库
        X_ERR_IPRGB_THIS_UNCREATED       = 0x00000102,  ///< 当前对象未创建
        X_ERR_IPRGB_PARAM_INVALID        = 0x00000103,  ///< 输入参数无效
        X_ERR_IPRGB_CREATE_BITMAP        = 0x00000104,  ///< 创建 BITMAP 对象失败
        X_ERR_IPRGB_NEW_IMGOBJ           = 0x00000105,  ///< 新建 IMAGE 对象失败
        X_ERR_IPRGB_NEW_PAGE             = 0x00000106,  ///< 新建 PAGE 对象失败

        //======================================
        // insert_page_by_jpegfile() 接口产生的错误码

        X_ERR_IPJPG_PDFLIB_NOT_LOADED    = 0x00000201,  ///< 尚未加载 PDF 库
        X_ERR_IPJPG_THIS_UNCREATED       = 0x00000202,  ///< 当前对象未创建
        X_ERR_IPJPG_PARAM_INVALID        = 0x00000203,  ///< 输入参数无效
        X_ERR_IPJPG_FILE_ACCESSOR        = 0x00000204,  ///< 构建 文件访问器 对象失败
        X_ERR_IPJPG_NEW_IMGOBJ           = 0x00000205,  ///< 新建 IMAGE 对象失败
        X_ERR_IPJPG_NEW_PAGE             = 0x00000206,  ///< 新建 PAGE 对象失败
        X_ERR_IPJPG_LOAD_JPGFILE         = 0x00000207,  ///< 加载 JPG 文件时失败

        //======================================
        // save_to_file() 接口产生的错误码

        X_ERR_SAVE_PDFLIB_NOT_LOADED     = 0x00000301,  ///< 尚未加载 PDF 库
        X_ERR_SAVE_THIS_UNCREATED        = 0x00000302,  ///< 当前对象未创建
        X_ERR_SAVE_PARAM_INVALID         = 0x00000303,  ///< 输入参数无效
        X_ERR_SAVE_FILE_WRITOR           = 0x00000304,  ///< 构建 文件写操作器 对象失败
        X_ERR_SAVE_FILE_DOCUMENT         = 0x00000305,  ///< 调用 SaveAsCopy() 时失败

        //======================================

    } xerrno_table_t;

    // common invoking
public:
    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_int32_t xit_errno)
    {
        x_cstring_t xszt_name = "UNDEFIND NAME";

        switch (xit_errno)
        {
        //======================================
        // create() 接口产生的错误码

        case X_ERR_CREATE_PDFLIB_NOT_LOADED  : xszt_name = "X_ERR_CREATE_PDFLIB_NOT_LOADED" ; break;
        case X_ERR_CREATE_XFUNC_CREATENEWDOC : xszt_name = "X_ERR_CREATE_XFUNC_CREATENEWDOC"; break;

        //======================================
        // insert_page_by_rgb32() 接口产生的错误码

        case X_ERR_IPRGB_PDFLIB_NOT_LOADED   : xszt_name = "X_ERR_IPRGB_PDFLIB_NOT_LOADED"; break;
        case X_ERR_IPRGB_THIS_UNCREATED      : xszt_name = "X_ERR_IPRGB_THIS_UNCREATED"   ; break;
        case X_ERR_IPRGB_PARAM_INVALID       : xszt_name = "X_ERR_IPRGB_PARAM_INVALID"    ; break;
        case X_ERR_IPRGB_CREATE_BITMAP       : xszt_name = "X_ERR_IPRGB_CREATE_BITMAP"    ; break;
        case X_ERR_IPRGB_NEW_IMGOBJ          : xszt_name = "X_ERR_IPRGB_NEW_IMGOBJ"       ; break;
        case X_ERR_IPRGB_NEW_PAGE            : xszt_name = "X_ERR_IPRGB_NEW_PAGE"         ; break;

        //======================================
        // insert_page_by_jpegfile() 接口产生的错误码

        case X_ERR_IPJPG_PDFLIB_NOT_LOADED   : xszt_name = "X_ERR_IPJPG_PDFLIB_NOT_LOADED"; break;
        case X_ERR_IPJPG_THIS_UNCREATED      : xszt_name = "X_ERR_IPJPG_THIS_UNCREATED"   ; break;
        case X_ERR_IPJPG_PARAM_INVALID       : xszt_name = "X_ERR_IPJPG_PARAM_INVALID"    ; break;
        case X_ERR_IPJPG_FILE_ACCESSOR       : xszt_name = "X_ERR_IPJPG_FILE_ACCESSOR"    ; break;
        case X_ERR_IPJPG_NEW_IMGOBJ          : xszt_name = "X_ERR_IPJPG_NEW_IMGOBJ"       ; break;
        case X_ERR_IPJPG_NEW_PAGE            : xszt_name = "X_ERR_IPJPG_NEW_PAGE"         ; break;
        case X_ERR_IPJPG_LOAD_JPGFILE        : xszt_name = "X_ERR_IPJPG_LOAD_JPGFILE"     ; break;

        //======================================
        // save_to_file() 接口产生的错误码

        case X_ERR_SAVE_PDFLIB_NOT_LOADED    : xszt_name = "X_ERR_SAVE_PDFLIB_NOT_LOADED"; break;
        case X_ERR_SAVE_THIS_UNCREATED       : xszt_name = "X_ERR_SAVE_THIS_UNCREATED"   ; break;
        case X_ERR_SAVE_PARAM_INVALID        : xszt_name = "X_ERR_SAVE_PARAM_INVALID"    ; break;
        case X_ERR_SAVE_FILE_WRITOR          : xszt_name = "X_ERR_SAVE_FILE_WRITOR"      ; break;
        case X_ERR_SAVE_FILE_DOCUMENT        : xszt_name = "X_ERR_SAVE_FILE_DOCUMENT"    ; break;

        //======================================

        default: break;
        }

        return xszt_name;
    }

    /**********************************************************/
    /**
     * @brief 获取 xerrno_table_t 中的错误码名称。
     */
    static x_cstring_t xerrno_name(x_errno_t xerr_no)
    {
        return xerrno_name(XERR_HINO(xerr_no));
    }

    // constructor/destuctor
public:
    XPDF_writer_t(void);
    ~XPDF_writer_t(void);

    // public interfaces
public:
    /**********************************************************/
    /**
     * @brief 创建对象。
     * 
     * @param [in ] xpvt_reserved : 保留参数（可设置为 X_NULL）。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t create(x_pvoid_t xpvt_reserved);

    /**********************************************************/
    /**
     * @brief 销毁对象操作接口。
     */
    x_void_t destroy(void);

    /**********************************************************/
    /**
     * @brief 对象是否处于 已经创建成功 的状态。
     */
    inline x_bool_t is_created(void) const
    {
        return (X_NULL != m_xht_fdocument);
    }

    /**********************************************************/
    /**
     * @brief 获取页面数量。
     */
    x_int32_t get_page_count(void) const;

    /**********************************************************/
    /**
     * @brief 使用 RGB32 像素数据构建页面。
     * 
     * @param [in ] xit_index : 页面索引号。
     * @param [in ] xit_pcx   : 页面宽度。
     * @param [in ] xit_pcy   : 页面高度。
     * @param [in ] xbits_ptr : RGB32 (BGRA 顺序)的像素数据的缓存。
     * @param [in ] xit_pitch : RGB32 (BGRA 顺序)的像素数据的缓存行步进大小。
     * @param [in ] xit_icx   : 图像宽度。
     * @param [in ] xit_icy   : 图像高度。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t insert_page_by_rgb32(
                        x_int32_t xit_index,
                        x_int32_t xit_pcx,
                        x_int32_t xit_pcy,
                        x_pvoid_t xbits_ptr,
                        x_int32_t xit_pitch,
                        x_int32_t xit_icx,
                        x_int32_t xit_icy);

    /**********************************************************/
    /**
     * @brief 使用 JPEG 图片文件构建页面。
     * 
     * @param [in ] xit_index : 页面索引号。
     * @param [in ] xszt_path : JPEG 图片文件路径名。
     * @param [in ] xit_pcx   : 页面宽度。
     * @param [in ] xit_pcy   : 页面高度。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t insert_page_by_jpegfile(
                        x_int32_t   xit_index,
                        x_cstring_t xszt_path,
                        x_int32_t   xit_pcx,
                        x_int32_t   xit_pcy);

    /**********************************************************/
    /**
     * @brief 将当前构建的 PDF 内容保存至文件中。
     * 
     * @param [in ] xszt_path : 存储的文件路径。
     * 
     * @return x_errno_t : 错误码。
     * @retval X_ERR_OK, 操作成功。
     * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
     * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
     */
    x_errno_t save_to_file(x_cstring_t xszt_path);

    // data members
private:
    x_handle_t      m_xht_fdocument;     ///< 文件构建的文档描述句柄
};

////////////////////////////////////////////////////////////////////////////////

#endif // __PDF_WRAPPER_H__
